package com.wjm.blog.common.exception;

import com.google.common.collect.Lists;
import com.wjm.blog.common.base.response.Result;
import com.wjm.blog.common.enums.ResponseEnum;
import com.wjm.blog.common.util.MessageUtil;
import com.wjm.blog.common.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;

/**
 * @Description: 全局异常处理类
 * @Author: Ailos
 * @Date: 2020/4/20 11:25
 * @Version: 1.0
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

	/**
	 * 处理自定义的业务异常
	 */
	@ExceptionHandler(value = BizException.class)
	@ResponseBody
	public Result bizExceptionHandler(BizException e) {
		log.error("发生业务异常！异常信息：{}", e.getMsg());
		String code = ResponseEnum.ERROR.getCode();
		if (StringUtil.isNotEmpty(e.getCode())) {
			code = e.code;
		}
		return Result.error(code, e.getMsg(), e.getArgs());
	}

	/**
	 * 参数绑定校验异常
	 */
	@ExceptionHandler(value = BindException.class)
	@ResponseBody
	public Result bindException(BindException e) {
		log.error("参数绑定校验异常！异常信息: ", e);
		// 获取绑定错误的字段名返回
		List<String> errorMessageList = Lists.newArrayList();
		for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
			String code = fieldError.getCode();
			String field = fieldError.getField();
			String m = fieldError.getDefaultMessage();
			// 非空校验，统一处理, 国际化信息提示
			if ("NotBlank".equalsIgnoreCase(code) || "NotNull".equalsIgnoreCase(code)) {
				errorMessageList
						.add(String.format(MessageUtil.getMessage(ResponseEnum.PARAM_NOT_NULL.getMessage()), field));
			} else {
				errorMessageList.add(MessageUtil.getMessage(m));
			}
		}
		return Result.error(ResponseEnum.ERROR.getCode(), errorMessageList.toString());
	}

	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseBody
	public Result handlerConstraintViolationException(ConstraintViolationException e) {
		log.error("参数绑定校验异常！异常信息: ", e);
		// 获取绑定错误的字段名返回
		List<String> errorMessageList = Lists.newArrayList();

		Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
		for (ConstraintViolation<?> constraintViolation : constraintViolations) {
			Annotation annotaion = constraintViolation.getConstraintDescriptor().getAnnotation();
			String path = constraintViolation.getPropertyPath().toString();
			String field = path.substring(path.lastIndexOf(".") + 1);
			String message = constraintViolation.getMessage();
			// 非空校验，统一处理, 国际化信息提示
			if (annotaion instanceof NotNull || annotaion instanceof NotBlank) {
				errorMessageList
						.add(String.format(MessageUtil.getMessage(ResponseEnum.PARAM_NOT_NULL.getMessage()), field));
			} else {
				errorMessageList.add(MessageUtil.getMessage(message));
			}
		}

		return Result.error(ResponseEnum.ERROR.getCode(), errorMessageList.toString());
	}

	/**
	 * 处理参数校验的业务异常
	 */
	@ExceptionHandler(value = RuntimeException.class)
	@ResponseBody
	public Result runtimeExceptionHandler(RuntimeException e) {
		e.printStackTrace();
		return Result.error(ResponseEnum.ERROR.getCode(), e.getMessage());
	}

	/**
	 * 处理参数校验的业务异常
	 */
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	@ResponseBody
	public Result methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
		log.error("发生参数校验异常！异常信息：", e);
		List<String> errorMessageList = Lists.newArrayList();
		for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
			String code = fieldError.getCode();
			String field = fieldError.getField();
			String m = fieldError.getDefaultMessage();
			// 非空校验，统一处理, 国际化信息提示
			if ("NotBlank".equalsIgnoreCase(code) || "NotNull".equalsIgnoreCase(code)) {
				errorMessageList
						.add(String.format(MessageUtil.getMessage(ResponseEnum.PARAM_NOT_NULL.getMessage()), field));
			} else {
				errorMessageList.add(MessageUtil.getMessage(m));
			}
		}
		return Result.error(ResponseEnum.ERROR.getCode(), errorMessageList.toString());
	}

	/**
	 * 处理其他异常
	 */
	@ExceptionHandler(value = Exception.class)
	@ResponseBody
	public Result exceptionHandler(Exception e) {
		log.error("未知异常！异常信息:", e);
		return Result.error(ResponseEnum.INTERNAL_SERVER_ERROR);
	}

	/**
	 * 处理其他异常
	 */
	@ExceptionHandler(value = Throwable.class)
	@ResponseBody
	public Result throwableHandler(Throwable t) {
		if (t instanceof BizException) {
			return this.bizExceptionHandler((BizException) t);
		} else {
			return this.exceptionHandler((Exception) t);
		}
	}
}
